#include "spi.h"
#include "stm32f429xx.h"

uint8_t spi5ReadWriteByte(uint8_t txdata) {
    while ((SPI5->SR & SPI_SR_TXE) == 0);  /* 等待发送区空 */
    SPI5->DR = txdata;                     /* 发送一个byte */
    while ((SPI5->SR & SPI_SR_RXNE) == 0); /* 等待接收完一个byte */
    return SPI5->DR;                       /* 返回收到的数据 */
}

void spi5SetSpeed(uint8_t speed) { // 基于84M Bit/s进行分频
    speed &= 0X07;                   /* 限制范围 */
    SPI5->CR1 &= ~(SPI_CR1_SPE_Msk); /* SPE = 0        , SPI设备失能 */
    SPI5->CR1 &= ~(SPI_CR1_BR);      /* BR[2:0] = 0    , 先清零 */
    SPI5->CR1 |= speed << 3;         /* BR[2:0] = speed, 设置分频系数 */
    SPI5->CR1 |= SPI_CR1_SPE;        /* SPE = 1        , SPI使能 */
}

void spi5Init(void) {
    uint32_t tempreg = 0;

    RCC->APB2ENR |= RCC_APB2ENR_SPI5EN; // 使能 SPI5 时钟
    RCC->AHB1ENR |= RCC_AHB1ENR_GPIOFEN; // 使能 GPIOF 时钟
    // SPI5 的引脚：PF7 (SCK)、PF8 (MOSI)、PF9 (MISO)
    // 清除 PF7,8,9 的模式位
    GPIOF->MODER &= ~(GPIO_MODER_MODE7_Msk|GPIO_MODER_MODE8_Msk|GPIO_MODER_MODE9_Msk);
    // 设置 PF7,8,9 为复用模式
    GPIOF->MODER |= (GPIO_MODER_MODE7_1|GPIO_MODER_MODE8_1|GPIO_MODER_MODE9_1);
    // 设置 PF7,8,9 为推挽输出(清除模式)
    GPIOF->OTYPER &= ~(GPIO_OTYPER_OT_7|GPIO_OTYPER_OT_8|GPIO_OTYPER_OT_9); 
    // 清除 PF7,8,9 的速度位
    GPIOF->OSPEEDR &= ~(GPIO_OSPEEDR_OSPEED7_Msk|GPIO_OSPEEDR_OSPEED8_Msk|GPIO_OSPEEDR_OSPEED9_Msk);
    // 设置 PF7,8,9 为高速(输入引脚该位无效)
    GPIOF->OSPEEDR |= (GPIO_OSPEEDR_OSPEED7_0|GPIO_OSPEEDR_OSPEED7_1|GPIO_OSPEEDR_OSPEED8_0|GPIO_OSPEEDR_OSPEED8_1|GPIO_OSPEEDR_OSPEED9_0|GPIO_OSPEEDR_OSPEED9_1); 
    // 清除 PF7,8,9 的上下拉配置
    GPIOF->PUPDR &= ~(GPIO_PUPDR_PUPD7_Msk|GPIO_PUPDR_PUPD8_Msk|GPIO_PUPDR_PUPD9_Msk); 
    // 设置 PF7,8,9 为上拉
    GPIOF->PUPDR |= (GPIO_PUPDR_PUPD7_0|GPIO_PUPDR_PUPD8_0|GPIO_PUPDR_PUPD9_0); 

    // 设置为 AF5(SPI)
    GPIOF->AFR[0] &= ~(GPIO_AFRL_AFRL7); // 清除 AFL
    GPIOF->AFR[0] |= (GPIO_AFRL_AFRL7_2|GPIO_AFRL_AFRL7_0); // 设置AFRL AF5
    GPIOF->AFR[1] &= ~(GPIO_AFRH_AFRH0|GPIO_AFRH_AFRH1); // 清除 AFH
    GPIOF->AFR[1] |= (GPIO_AFRH_AFRH0_2|GPIO_AFRH_AFRH0_0|GPIO_AFRH_AFRH1_2|GPIO_AFRH_AFRH1_0); // 设置AFRH AF5

    // 设置SPI寄存器
    tempreg |= 0 << SPI_CR1_DFF_Pos;      /* DFF = 0      , 使用8位数据格式 */
    tempreg |= 0 << SPI_CR1_RXONLY_Pos;   /* RXONLY = 0   , 全双工模式 */
    tempreg |= 1 << SPI_CR1_SSM_Pos;      /* SSM = 1      , 软件片选(NSS)控制 */
    tempreg |= 1 << SPI_CR1_SSI_Pos;      /* SSI = 1      , 禁止软件从设备, 即做主机 */
    tempreg |= 0 << SPI_CR1_LSBFIRST_Pos; /* LSBFRST = 0  , MSB先传输 */
    tempreg |= 7 << SPI_CR1_BR_Pos;       /* BR[2:0] = 7  , 默认使用256分频, 速度最低 */
    tempreg |= 1 << SPI_CR1_MSTR_Pos;     /* MSTR = 1     , 主机模式 */
    tempreg |= 1 << SPI_CR1_CPOL_Pos;     /* CPOL = 1     , 空闲状态下, SCK保持高电平 */
    tempreg |= 1 << SPI_CR1_CPHA_Pos;     /* CPHA = 1     , 数据采集从第二个时钟边沿开始 */
    SPI5->CR1 = tempreg;

    SPI5->CR1 |= SPI_CR1_SPE; // SPE = 1 , SPI使能
    spi5ReadWriteByte(0xFF); // 启动传输, 实际上就是产生8个时钟脉冲, 达到清空DR的作用, 非必需
}
